/**
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package br.biofoco.p2p.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Collection;
import java.util.List;
import org.codehaus.jackson.JsonParseException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;

import br.biofoco.p2p.peer.IDFactory;
import br.biofoco.p2p.peer.PeerConfig;
import br.biofoco.p2p.rpc.EndPoint;
import br.biofoco.p2p.rpc.EndpointFactory;
import br.biofoco.p2p.rpc.InetAddressUtil;
import br.biofoco.p2p.rpc.Protocol;

/**
 * File System PeerConfigurator
 *  
 */
public class FSXmlPeerConfigurator implements PeerNodeConfigurator {

	private static final Logger LOGGER = LoggerFactory.getLogger(FSXmlPeerConfigurator.class);	
	private final String CONFIG_DIR;
	
	private EndpointFactory endpointFactory;

	@Inject
	public FSXmlPeerConfigurator(EndpointFactory endpointFactory) {		
		this.endpointFactory = endpointFactory;
		CONFIG_DIR = System.getProperty("config.dir", ConfigConstants.CONFIG_DIR);		
	}

	public PeerConfig getConfig() throws IOException, PeerConfigurationException {
		
		LOGGER.debug("Loading xml peer configuration...");
		
		PeerConfig peerConfig = new PeerConfig();		
		SAXReader reader = new SAXReader();		
		try {
			Document doc = reader.read(getInputStream(ConfigConstants.PEER_FILE));			
			Element root = doc.getRootElement();
			Element peerID = root.element("peerID");
			if (peerID != null)
				peerConfig.setPeerID(IDFactory.fromString(peerID.getTextTrim()));
			
//			Element peerName = root.element("peerName");
//			if (peerName != null)
//				peerConfig.setPeerName(peerName.getTextTrim());
			
			List<?> endpoints = root.element("endpoints").elements("endpoint");
			
			for (Object obj: endpoints) {
				
				Element el = (Element) obj;
				
				String address = getLocalAddress(el.element("address"));
				
				String proto = el.element("protocol").getTextTrim();
				String portStr = el.element("port").getTextTrim();				
				
				Protocol protocol = Protocol.of(proto);
				LOGGER.debug("-------------------- ENDEREÇO DE REDE: " + address);
				Integer port = Integer.parseInt(portStr); 
				EndPoint endpoint = endpointFactory.createEndpoint(protocol, address, port);

				peerConfig.add(endpoint);
			}
			
		} catch (DocumentException e) {
			throw new PeerConfigurationException(e.getMessage(), e);
		}
		
		return peerConfig;
		
	}
	
	private String getLocalAddress(Element element) {
		
		if (element != null){
			return element.getTextTrim();
		}
		
		
		try {
			
			List<InetAddress> addrs = InetAddressUtil.getLocalAddresses();
			
			return (addrs.size() == 0) ? "127.0.0.1" : addrs.get(0).getHostAddress();
			
		} catch (SocketException e) {
			e.printStackTrace();
			LOGGER.error(e.getMessage());
		}
		
		return "127.0.0.1";
		
	}
	

	private InputStream getInputStream(String filename) throws FileNotFoundException {
		return new FileInputStream(CONFIG_DIR + File.separator + filename);
	}

//	private OutputStream getOutputStream(String filename) throws IOException {
//		return new FileOutputStream(BASE_DIR + File.separator + ConfigConstants.CONFIG_DIR + File.separator + filename);
//	}

	public PeerConfig savePeerConfig(PeerConfig config) throws PeerConfigurationException, JsonParseException, IOException {

		throw new UnsupportedOperationException("Operation not supported!");
		
//		LOGGER.debug("Saving new version of file ");
//		try {
//			OutputStream os = getOutputStream(ConfigConstants.PEER_FILE);
//			
//			XStream xstream = new XStream();
//			xstream.alias("peerConfig", PeerConfig.class);
//			xstream.toXML(config, os);
//			os.close();
//			LOGGER.debug("File sucessfuly updated.");
//			
//		} catch (IOException e) {
//			throw new PeerConfigurationException(e.getMessage(), e);
//		}
//		return config;
	}

	public Collection<String> loadSeedList() throws PeerConfigurationException {
		throw new UnsupportedOperationException("Operation not supported!");
//		try {
//			InputStream input = getInputStream(ConfigConstants.SEED_FILE);
//			XStream xstream = new XStream();
//			List<String> list = (List<String>) xstream.fromXML(input);
//			return ImmutableList.copyOf(list);
//		} catch (IOException e) {
//			return ImmutableList.of();
//		}
	}

	public String serializePeerConfig(PeerConfig peerConfig) {
		
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("peerConfig");
        
        root.addElement("peerID").addText(peerConfig.getPeerID().toString());        
//        root.addElement("peerName").addText(peerConfig.getPeerName());
        Element endpoints = root.addElement("endpoints");
        
        for (EndPoint e : peerConfig.getEndPoints()){
        	endpoints.addElement("endpoint").addElement("protocol").addText(e.getProtocol().toString());
        	endpoints.addElement("endpoint").addElement("port").addText("" + e.getPort());
        }
        
        return document.asXML();
	}
}
